package com.qijian.spider;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.qijian.common.utils.file.AliyunOSSUtil;
import com.qijian.common.utils.uuid.IdUtils;
import com.qijian.system.domain.SysConfig;
import com.qijian.system.service.ISysConfigService;
import com.qijian.tool.domain.Storage;
import com.qijian.tool.service.IStorageService;
import liquibase.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Component
public abstract class FanWeiBase extends BaseOkHttp3Client {

    @Autowired
    private ISysConfigService configService;
    @Autowired
    private IStorageService storageService;

    protected static final String DETAIL_KEY = "data_main_detail";


    protected static final String REQ_LOG_LIST_KEY = "data_main_logs";

    protected static final String Key_Base = "SYNC_";
    protected static final int MAX_PAGE_SIZE = 500;

    protected static final String host = "http://oa.zjavim.com:8082";
    private static final String loginPath = host + "/api/hrm/login/checkLogin";
    private static final String listCountPath = host + "/api/ec/dev/table/counts";
    private static final String listDataPath = host + "/api/ec/dev/table/datas";


    private static final String username = "13814896462";
    private static final String password = "xrw.1234";

    protected final Map<Integer, Map<Object, String>> columnDateSelector = new HashMap<>();
    private final Map<Long, JSONObject> userInfoCache = new HashMap<>();

    protected abstract String getConfigValueKey();

    protected abstract Function<String, Integer> doSomeThing();

    protected abstract String getSessionKey(String yearMonth);

    @Transactional(rollbackFor = Exception.class)
    public void door() {
        increment();
    }

    void increment() {
        SysConfig config = null;
        if (getConfigValueKey() != null)
            config = configService.selectConfigByKeyVal(getConfigValueKey());
        if (config != null) {
            login();
            Integer dataSize = doSomeThing().apply(config.getConfigValue());
            if (dataSize > 0) {
                SysConfig update = new SysConfig();
                update.setConfigId(config.getConfigId());
                update.setConfigValue(LocalDate.now().plusDays(-1).toString());
                configService.updateConfig(update);
            }
        } else {
            login();
            doSomeThing().apply(null);
        }
    }

    protected void login() {
//        String params = "?islanguid=7&loginid=" + username + "&userpassword=" + password + "&dynamicPassword=" +
//                "&tokenAuthKey=&validatecode=&validateCodeKey=&logintype=1&messages=&isie=false&";
        String params = "?islanguid=7&loginid=PwCeSWfD0HN6OOjUxq1pTa0yJyLFhcVVf%2F7puk2nCPCYsBz%2BYKdKuUBhK8wY%2BAssjXGAYHu0V0IOnTcoWGkcRA8TgL46uKKUrLPplEPj7WuSz4hwp%2BZ9F6f881ycSf%2BaXPzFP33GcZ3qMVWzYUBhS3ljfGtfCtgIh6N12rAy2miQGKaIrpROb6bkdMM1qcLNGRe6uNQj5gvlATIn2ZTzi37fgJbjDocDMF0%2BucBzcEKaYo2iTk1zFiWTd4KJ%2BAH2UQmxxUFL3%2B9stwdl6dXmidGA%2B%2BEMZExOa%2Bk2APPYRds5frPjNDZUtEwxpx08pQv7mE2Le20AGj68oEEintCamA%3D%3D%60%60RSA%60%60&userpassword=gc7IwAgj86Kx6rPnvDA53uNeSiYzoaRJUJIQy0mDr8oQz8mDXuIbkM%2Bdy%2Fo6%2Fr19uWx8EfApoTXuUHwKhzbYxjKNvN1SjI8AFBEIUHm%2BDfJiqDkp7MdCV9vCDDxeUzIlgr%2F6djtJ0H%2Bu7a1hcUYFz4vOlPIN7ijzJzw7gzfGVUQbqwLLtwY2Qy8kJBElZtQGaSRdRvUhwFx4c%2F5Yu6%2BZkQf0D7cTc%2F8NzUfEROLYR2zjx%2Bn8tTEjH97cxkO9%2FXU7Wrb%2BJYst3nimJ5TB8jJTaWzW%2FJjTDFjczTvwwS11NfRhQyfdCArp%2Btquiwocx10EghPt0PrwZC02urB%2FAa3z7A%3D%3D%60%60RSA%60%60&dynamicPassword=&tokenAuthKey=&validatecode=&validateCodeKey=&logintype=1&messages=&isie=false&";
        String s = doPost(loginPath + params);
        if (StrUtil.isEmpty(s))
            throw new RuntimeException("泛微系统登陆失败");
        JSONObject result = JSONUtil.parseObj(s);
        if (result.getBool("loginstatus")) {
            log.info("泛微系统登陆成功");
        } else {
            throw new RuntimeException("泛微系统登陆失败:" + result.getStr("msg"));
        }
    }

    protected void setPageSize(String sessionKey, int pageSize) {
        if (StrUtil.isEmpty(sessionKey))
            throw new RuntimeException("泛微NCR设置分页缺少sessionKey");
        String params = "?dataKey=" + sessionKey + "&pageSize=" + pageSize + "&";
        String pageSizeUrl = host + "/api/ec/dev/table/pageSize" + params;
        String s = doPost(pageSizeUrl);

        if (StrUtil.isEmpty(s) || !JSONUtil.parseObj(s).getBool("status"))
            throw new RuntimeException("泛微NCR设置分页失败：" + s);
    }

    private int getListCount(String sessionKey) {
        if (StrUtil.isEmpty(sessionKey))
            return 0;
        String countUrl = listCountPath + "?dataKey=" + sessionKey;
        String s = doPost(countUrl);
        return JSONUtil.parseObj(s).getInt("count");
    }

    private JSONObject getListData(String sessionKey, int page) {
        if (StrUtil.isEmpty(sessionKey))
            throw new RuntimeException("泛微NCR获取列表数据缺少sessionKey");
        String params = "?dataKey=" + sessionKey + "&current=" + page + "&sortParams=%5B%5D&";
        String countUrl = listDataPath + params;
        String s = doPost(countUrl);
        if (StrUtil.isEmpty(s))
            throw new RuntimeException("泛微NCR获取列表数据异常");
        return JSONUtil.parseObj(s);
    }

    protected JSONArray loadData(String sessionKey) {
        int totalCount = getListCount(sessionKey);
        if (totalCount <= 0)
            return null;
        if (totalCount > 10)
            setPageSize(sessionKey, Math.min(totalCount, MAX_PAGE_SIZE));
        JSONObject obj = getListData(sessionKey, 1);
        Integer pageSize = obj.getInt("pageSize");

        if (totalCount <= pageSize)
            return obj.getJSONArray("datas");
        JSONArray allData = new JSONArray(obj.getJSONArray("datas"));

        int totalPage = (totalCount + pageSize - 1) / pageSize;
        for (int i = 2; i <= totalPage; i++) {
            JSONObject data = getListData(sessionKey, i);
            if (!data.getInt("pageSize").equals(pageSize)) {
                throw new RuntimeException("泛微NCR 分页参数异常 获取数据无法保证完整!");
            }
            allData.addAll(data.getJSONArray("datas"));
        }
        return allData;
    }

    protected void initParams(JSONObject obj, Integer... key) {
        JSONObject tableInfo = obj.getJSONObject("tableInfo").getJSONObject("main").getJSONObject("fieldinfomap");
        initFieldInfoMap(tableInfo, key);
    }

    private void initFieldInfoMap(JSONObject tableInfo, Integer... key) {
        for (Integer integer : key) {
            this.columnDateSelector.put(integer, tableInfo.getJSONObject(String.valueOf(integer))
                    .getJSONObject("selectattr")
                    .getJSONArray("selectitemlist")
                    .stream().map(JSONUtil::parseObj).collect(Collectors.toMap(d -> d.getInt("selectvalue"), d -> d.getStr("selectname"))));
        }
    }


    protected String getFieldValue(JSONObject o, String field) {
        return o.getJSONObject(field).getStr("value");
    }

    protected BigDecimal getFieldValueBigdecimal(JSONObject o, String field) {
        return o.getJSONObject(field).getBigDecimal("value");
    }

    protected Integer getFieldValueInt(JSONObject o, String field) {
        return o.getJSONObject(field).getInt("value");
    }

    protected String getSpecialObjName(JSONObject obj, String key) {
        JSONArray array = obj.getJSONObject(key).getJSONArray("specialobj");
        if (CollectionUtil.isEmpty(array))
            return null;
        return array.stream().map(d -> JSONUtil.parseObj(d).getStr("name")).collect(Collectors.joining(","));
    }

    protected String getSpecialObjNameOne(JSONObject obj, String key) {
        JSONArray array = obj.getJSONObject(key).getJSONArray("specialobj");
        if (CollectionUtil.isEmpty(array))
            return null;
        return array.getJSONObject(0).getStr("name");
    }

    protected List<Storage> transformStorageFile(JSONObject main, Long mainId, String classTable, String filedName, Integer classify) {
        List<Storage> result = new ArrayList<>();
        JSONArray file1 = main.getJSONObject(filedName).getJSONObject("specialobj").getJSONArray("filedatas");
        if (file1.size() > 0) {
            List<Storage> storages = file1.stream().map(obj -> {
                JSONObject d = JSONUtil.parseObj(obj);
                Storage storage = Storage.instance(mainId, classTable
                        , d.getStr("filename"), host + d.getStr("loadlink"), d.getStr("filesize"));
                storage.setFid(d.getLong("fileid"));
                storage.setClassify(classify);
                return storage;
            }).collect(Collectors.toList());
            result.addAll(storages);
        }
        return result;
    }

    protected void saveFiles(List<Storage> storages, String classTable, String folder) {
        try {
            List<Long> fids = storageService.filterFids(classTable, storages.stream().map(Storage::getFid).collect(Collectors.toList()));
            storages = storages.stream().filter(s -> !fids.contains(s.getFid())).collect(Collectors.toList());
            if (storages.size() > 0) {
                storages.forEach(s -> {
                    final byte[] bytes = super.downloadFile(s.getUrl());
                    String aliPath = AliyunOSSUtil.uploadObject2OSS(AliyunOSSUtil.getOSSClient(), new ByteArrayInputStream(bytes), "fanwei/" + folder + "/" + s.getType(), String.format("%s.%s", IdUtils.fastSimpleUUID(), s.getSuffix()));
                    s.setUrl(aliPath);
                    storageService.save(s);
                });
            }
        } catch (Exception ex) {
            //ignore
        }
    }

    protected JSONObject getUserInfo(Long userId) {
        if (!userInfoCache.containsKey(userId))
            userInfoCache.put(userId, getUserInfoByUrl(userId));
        return userInfoCache.get(userId);
    }

    private JSONObject getUserInfoByUrl(long userId) {
        String s = doGet(host + "/api/hrm/simpleinfo/getHrmSimpleInfo?userid=" + userId + "&__random__=" + System.currentTimeMillis());
        if (StringUtil.isEmpty(s))
            throw new RuntimeException("获取泛微用户信息失败");
        return JSONUtil.parseObj(s);
    }

    protected static Long str2Long(Long pre, String str) {
        String s = pre + str2Long(str);
        if (s.length() > 19)
            s = s.substring(s.length() - 19);
        return Long.valueOf(s);
    }

    protected static String str2Long(String str) {
        List<String> strList = ListUtil.sub(ReUtil.findAllGroup0("[A-Za-z]", str), 0, 3);
        List<String> intList = ReUtil.findAllGroup0("\\d", str);
        String collect = strList.stream().map(d -> {
            StringBuilder result = new StringBuilder();
            for (char c : d.toCharArray()) {
                result.append((int) c);
            }
            return result.toString();
        }).collect(Collectors.joining());
        return collect + String.join("", intList);
    }

    protected String getUserName(JSONObject userInfo) {
        return userInfo.getStr("lastname");
    }

    protected String getDeptName(JSONObject userInfo) {
        return userInfo.getStr("departmentName");
    }

}
